local snow    = require("meet_your_mods.mhr").snow
local setting = require("meet_your_mods.setting")
local ui      = require("meet_your_mods.ui")

local damage_text = {
    setting = {
        hide_otomo              = true,  --关闭随从伤害显示
        show_physical_weakness  = true,  --提示物理弱点
        show_elemental_weakness = true, --提示属性弱点
        show_truely             = true,  --提示无视肉质的伤害
        show_critical           = true,  --提示正负会心
        show_details            = false, --显示伤害构成
    },
    weakness_rate = {
        physical         = 0.445, --弱点特效肉质
        elemental_soft   = 0.25,  --百龙珠属性弱点特效肉质
        elemental_normal = 0.2,   --属性弱点特效肉质
    },
    elemental_level = {
        soft   = 1,
        normal = 2,
        hard   = 3,
    },
    critical_text = {
        [snow.hit.CriticalType.None]             = nil,
        [snow.hit.CriticalType.Critical]         = "<COLOR FFFF00>*</COLOR>",
        [snow.hit.CriticalType.NegativeCritical] = "<COLOR 4169E1>*</COLOR>",
    },
    weakness_text = {
        [1] = "<COLOR 00FFFF>*</COLOR>",
        [2] = "<COLOR 4040FF>*</COLOR>",
        [3] = nil,
    },
    damage    = nil,
    damage_ui = nil,
    data      = {
        type           = 0,
        owner          = 0,
        physical_rate  = 0.0,
        elemental_rate = 0.0,

        total    = 0.0,
        critical = 0,
        physical = 0.0,
        elemental      = 0.0,
        elemental_type = 0,
    },
}

--伤害数字增强
function damage_text:pre_getHitUIColorType(parameters)
    if self.setting.hide_otomo
        or self.setting.show_physical_weakness
        or self.setting.show_elemental_weakness
        or self.setting.show_truely
        or self.setting.show_critical
        or self.setting.show_details
    then
        local instance = snow.hit.EnemyCalcDamageInfo.AfterCalcInfo_DamageSide(sdk.to_managed_object(parameters[2]))
        local details  = instance._CalcParam

        self.data.type  = details:get_CalcType()
        self.data.owner = details:get_OwnerType()
        self.data.physical_rate  = details:get_PhysicalMeatAdjustRate()
        self.data.elemental_rate = details:get_ElementMeatAdjustRate()

        self.data.total    = instance:get_TotalDamage()
        self.data.critical = instance:get_CriticalResult()
        self.data.physical = instance:get_PhysicalDamage()
        self.data.elemental      = instance:get_ElementDamage()
        self.data.elemental_type = instance:get_ElementType()
        self.damage = self.data
    end
    return sdk.PreHookResult.CALL_ORIGINAL
end

function damage_text:post_getHitUIColorType(result)
    if not self.damage then
        return result
    end

    --隐藏随从伤害数字
    local damage_color = sdk.to_int64(result)
    if (snow.hit.DamageFlowOwnerType.Otomo         == self.damage.owner
        or snow.hit.DamageFlowOwnerType.OtomoShell == self.damage.owner)
        and self.setting.hide_otomo
    then
        damage_color = snow.gui.GuiDamageDisp.ColorType.White - 1
    --设置玩家伤害数字
    elseif snow.hit.DamageFlowOwnerType.Player      == self.damage.owner
        or snow.hit.DamageFlowOwnerType.PlayerShell == self.damage.owner
    then
        --设置无视物理肉质伤害
        if snow.enemy.EnemyDef.DamageCalcType.IgnoreMeat == self.damage.type
            and self.setting.show_truely
        then
            damage_color = snow.gui.GuiDamageDisp.ColorType.Gray
        --设置物理弱点
        elseif self.setting.show_physical_weakness then
            --弱点特效肉质
            if self.damage.physical_rate > self.weakness_rate.physical then
                damage_color =  snow.gui.GuiDamageDisp.ColorType.Orange
            --近战的心眼肉质
            elseif (snow.enemy.EnemyDef.DamageCalcType.Slash      == self.damage.type
                    or snow.enemy.EnemyDef.DamageCalcType.Strike  == self.damage.type)
                    and snow.gui.GuiDamageDisp.ColorType.White == damage_color
            then
                damage_color = snow.gui.GuiDamageDisp.ColorType.Gray
            --普通物理肉质
            else
                damage_color = snow.gui.GuiDamageDisp.ColorType.White
            end
        end

        --设置属性弱点
        if self.setting.show_elemental_weakness
            and self.damage.elementtal_type ~= snow.enemy.EnemyDef.MeatAttr.Invalid
        then
            if self.damage.elemental_rate >= self.weakness_rate.elemental_soft then
                self.damage.elemental_weakness = self.elemental_level.soft
            elseif self.damage.elemental_rate >= self.weakness_rate.elemental_normal then
                self.damage.elemental_weakness = self.elemental_level.normal
            else
                self.damage.elemental_weakness = self.elemental_level.hard
            end
        end
    end

    return sdk.to_ptr(damage_color)
end

--变更伤害数字颜色/提示会心/提示属性弱点
function damage_text:pre_startNumDisp(parameters)
    if self.damage or self.setting.show_truely then
        self.damage_ui = snow.gui.GuiDamageDisp.NumDisp(sdk.to_managed_object(parameters[2]))._DamageText
    end
    return sdk.PreHookResult.CALL_ORIGINAL
end

function damage_text:post_startNumDisp(result)
    if not self.damage_ui then
        return result
    end

    if not self.damage then
        self.damage_ui:set_Message("<COLOR FF4040>"..self.damage_ui:get_Message().."</COLOR>")
        self.damage_ui = nil

        return result
    end

    if not self.setting.show_critical
        and not self.setting.show_elemental_weakness
        and not self.setting.show_truely
        and not self.setting.show_details
    then
        self.damage    = nil
        self.damage_ui = nil

        return result
    end

    --提示会心
    local critical_text = nil
    if self.setting.show_critical
        and self.damage.critical ~= snow.hit.CriticalType.None
    then
        critical_text = self.critical_text[self.damage.critical]
    end

    --提示属性弱点
    local weakness_text = nil
    if self.setting.show_elemental_weakness
        and self.damage.elemental_type ~= snow.enemy.EnemyDef.MeatAttr.Invalid
    then
        weakness_text = self.weakness_text[self.damage.elemental_weakness]
    end

    --组装伤害数字，变更无视物理肉质伤害的颜色
    local text = nil
    if self.setting.show_details then
        text =
            (snow.enemy.EnemyDef.DamageCalcType.IgnoreMeat == self.damage.type
                and self.setting.show_truely_damage
                and "<COLOR FF4040>" or "")
            .. math.floor(self.damage.physical)
            .. "/"
            .. math.floor(self.damage.elemental)
            ..  (snow.enemy.EnemyDef.DamageCalcType.IgnoreMeat == self.damage.type
                and self.setting.show_truely_damage
                and "</COLOR>" or "")
    elseif snow.enemy.EnemyDef.DamageCalcType.IgnoreMeat == self.damage.type
        and self.setting.show_truely
    then
        text = "<COLOR FF4040>" .. math.floor(self.damage.total) .. "</COLOR>"
    end

    --组装会心和属性弱点提示
    if critical_text then
        text = critical_text .. (text or math.floor(self.damage.total))
    end
    if weakness_text then
        text = (text or math.floor(self.damage.total)) .. weakness_text
    end
    if text then
        self.damage_ui:set_Message(text)
    end
    self.damage    = nil
    self.damage_ui = nil

    return result
end

function damage_text:initialize()
    snow.enemy.EnemyUtility.getHitUIColorType:sdk_auto_hook(self)
    snow.gui.GuiDamageDisp.NumDisp.startNumDisp:sdk_auto_hook(self)

    setting:bind_setting("damage_text", self.setting)

    ui:cluster("gui", "UI增强")
    ui:static_text("gui", "伤害显示")
    ui:checkbox("gui", "damage_text", "hide_otomo",              "关闭随从伤害数字", nil, true)
    ui:checkbox("gui", "damage_text", "show_physical_weakness",  "提示物理弱点", nil, true)
    ui:checkbox("gui", "damage_text", "show_elemental_weakness", "提示属性弱点", nil, true)
    ui:checkbox("gui", "damage_text", "show_truely",             "提示无视肉质的伤害", nil, true)
    ui:checkbox("gui", "damage_text", "show_critical",           "提示会心", nil, true)
    ui:checkbox("gui", "damage_text", "show_details",            "显示物属构成", nil, true)
end

function damage_text:normalize()
end

return damage_text